#pragma once

#include <cstring>
#include <assert.h>

namespace Simulation
{
    class string
    {
    public:
        typedef char *iterator;
        typedef const char *const_iterator;

    public:
        // 构造函数
        string(const char *str = "")
        {
            _size = strlen(str);
            _capacity = _size;
            _str = new char[_capacity + 1];
            strcpy(_str, str);
        }
        // 拷贝构造 传统写法
        string(const string &s)
        {
            // 深拷贝，另外开一块空间
            _size = s._size;
            _capacity = s._capacity;
            _str = new char[_capacity + 1];
            strcpy(_str, s._str);
        }

        // operator= 传统写法
        string &operator=(const string &s)
        {
            if (this != &s) // 防止自己给自己赋值
            {
                delete[] _str;
                _size = s._size;
                _capacity = s._capacity;
                _str = new char[_capacity + 1];
                strcpy(_str, s._str);
            }
            return *this;
        }
        iterator begin()
        {
            return _str;
        }
        iterator end()
        {
            return _str + _size;
        }
        const_iterator begin() const
        {
            return _str;
        }
        const_iterator end() const
        {
            return _str + _size;
        }
        char &operator[](size_t i)
        {
            assert(i < _size);
            return _str[i];
        }
        const char &operator[](size_t i) const
        {
            assert(i < _size);
            return _str[i];
        }
        size_t size() const
        {
            return _size;
        }

        size_t capacity() const
        {
            return _capacity;
        }

        const char *c_str() const
        {
            return _str;
        }

        // 增
        void reserve(size_t n)
        {
            if (n > _capacity)
            {
                char *newStr = new char[n + 1];
                strcpy(newStr, _str);
                delete[] _str;
                _str = newStr;

                _capacity = n;
            }
        }
        void push_back(char ch)
        {
            insert(_size, ch);
        }
        void append(const char *str)
        {
            insert(_size, str);
        }
        // operator+=
        string &operator+=(char ch)
        {
            push_back(ch);
            return *this;
        }
        string &operator+=(const char *s)
        {
            append(s);
            return *this;
        }
        string operator+(char ch)
        {
            string tmp(_str);
            tmp.push_back(ch);
            return tmp;
        }
        ~string()
        {
            delete[] _str;
            _str = nullptr;
            _size = _capacity = 0;
        }

        void resize(size_t n, char ch = '\0')
        {
            if (n > _capacity)
            {
                size_t newcapacity = n;
                reserve(newcapacity);
            }
            // _size>=n时不进入循环
            for (size_t i = _size; i < n; ++i)
            {
                _str[i] = ch;
            }

            _size = n;
            _str[_size] = '\0'; // 注意
        }
        string &insert(size_t pos, char ch)
        {
            assert(pos <= _size);
            // 扩容
            if (_size == _capacity)
            {
                size_t newcapacity = _capacity == 0 ? 2 : _capacity * 2;
                reserve(newcapacity);
            }
            memmove(_str + pos + 1, _str + pos, sizeof(char) * (_size - pos));
            _str[pos] = ch;
            _size++;
            _str[_size] = '\0'; // 注意

            return *this;
        }
        string &insert(size_t pos, const char *s)
        {
            assert(pos <= _size);
            size_t len = strlen(s);
            // 扩容
            if (len + _size > _capacity)
            {
                size_t newcapcity = len + _size;
                reserve(newcapcity);
            }
            memmove(_str + pos + len, _str + pos, sizeof(char) * (_size - pos));
            // strcpy(_str + pos, s);  最后会把'\0'拷过去
            strncpy(_str + pos, s, len);
            _size += len;
            _str[_size] = '\0'; // 注意

            return *this;
        }
        void clear()
        {
            _size = 0; // _capacity  底层空间不变
            _str[0] = '\0';
        }
        bool operator==(const string &s) const
        {
            return strcmp(_str, s._str) == 0;
        }

        bool operator!=(const string &s) const
        {
            return strcmp(_str, s._str) != 0;
        }

    private:
        char *_str;
        size_t _size;     // 有效字符个数
        size_t _capacity; // 能存储的有效字符的个数 '\0'不是有效字符，是标识结束的字符
    };

    std::ostream &operator<<(std::ostream &out, const string &s)
    {
        for (size_t i = 0; i < s.size(); i++)
        {
            out << s[i];
        }
        return out;
    }
    std::istream &operator>>(std::istream &in, string &s)
    {
        s.clear();
        while (1)
        {
            char ch;
            ch = in.get();
            if (ch == ' ' || ch == '\n')
            {
                break;
            }
            else
            {
                s += ch;
            }
        }
        return in;
    }
}